From be48530a798adf89ad8efdb0d6229603d5e5de6f Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C3=98yvind=20Kol=C3=A5s?= Date: Sun, 18 Sep 2005 21:00:05 +0000 Subject: [PATCH] importing BablFishPath --- babl/Makefile.am | 3 + babl/babl-conversion.c | 250 ++++++++++++++++++-- babl/babl-core.c | 44 +++- babl/babl-db.c | 7 + babl/babl-db.h | 1 + babl/babl-fish-path.c | 420 ++++++++++++++++++++++++++++++++++ babl/babl-fish-reference.c | 338 +++++++++++++++++++++++++++ babl/babl-fish-simple.c | 57 +++++ babl/babl-fish.c | 452 ++++++++----------------------------- babl/babl-format.c | 124 +++++++++- babl/babl-internal.c | 116 ++++------ babl/babl-internal.h | 82 ++++--- babl/babl-introspect.c | 1 + babl/babl-model.c | 144 +++++++++++- babl/babl-sanity.c | 2 +- babl/babl-type.c | 99 ++++++++ 16 files changed, 1655 insertions(+), 485 deletions(-) create mode 100644 babl/babl-fish-path.c create mode 100644 babl/babl-fish-reference.c create mode 100644 babl/babl-fish-simple.c diff --git a/babl/Makefile.am b/babl/Makefile.am index 2ca82e7..bcc92a4 100644 --- a/babl/Makefile.am +++ b/babl/Makefile.am @@ -15,6 +15,9 @@ c_sources = \ babl-conversion.c \ babl-extension.c \ babl-fish.c \ + babl-fish-simple.c \ + babl-fish-reference.c \ + babl-fish-path.c \ babl-format.c \ babl-image.c \ babl-internal.c \ diff --git a/babl/babl-conversion.c b/babl/babl-conversion.c index d308469..976f437 100644 --- a/babl/babl-conversion.c +++ b/babl/babl-conversion.c @@ -21,12 +21,12 @@ #include "babl-db.h" #include #include +#include static int each_babl_conversion_destroy (Babl *babl, void *data) { - babl_free (babl->instance.name); babl_free (babl); return 0; /* continue iterating */ } @@ -45,37 +45,48 @@ conversion_new (const char *name, babl_assert (source->class_type == destination->class_type); + babl = babl_malloc (sizeof (BablConversion) + strlen (name) + 1); + babl->instance.name = (void *)babl + sizeof (BablConversion); + strcpy(babl->instance.name, name); + if (linear) { - babl = babl_malloc (sizeof (BablConversion)); babl->class_type = BABL_CONVERSION_LINEAR; babl->conversion.function.linear = linear; } else if (plane) { - babl = babl_malloc (sizeof (BablConversion)); babl->class_type = BABL_CONVERSION_PLANE; babl->conversion.function.plane = plane; } else if (planar) { - babl = babl_malloc (sizeof (BablConversion)); babl->class_type = BABL_CONVERSION_PLANAR; babl->conversion.function.planar = planar; } switch (source->class_type) { case BABL_TYPE: - break; - case BABL_MODEL: - if (linear) + if (linear) /* maybe linear could take a special argument, passed as an + additional key/value pair in the constructor. To cast it + as a generic N-element conversion, thus making it applicable + to being generic for any within model conversion of plain + buffers. + */ { - babl_fatal ("linear support for %s not supported", + babl_fatal ("linear conversions not supported for %s", babl_class_name (source->class_type)); } - else if (plane) + else if (planar) { - babl_fatal ("plane support for %s not supported", + babl_fatal ("planar conversions not supported for %ssupported", + babl_class_name (source->class_type)); + } + break; + case BABL_MODEL: + if (plane) + { + babl_fatal ("plane conversions not supported for %s", babl_class_name (source->class_type)); } break; @@ -87,32 +98,72 @@ conversion_new (const char *name, } babl->instance.id = id; - babl->instance.name = babl_strdup (name); babl->conversion.source = (union Babl*)source; babl->conversion.destination = (union Babl*)destination; - babl->conversion.error = 0.0; + babl->conversion.error = -1.0; + babl->conversion.cost = 69; babl->conversion.pixels = 0; babl->conversion.processings = 0; - babl_add_ptr_to_list ((void ***)&(source->type.from), babl); - + if (babl->class_type == BABL_CONVERSION_LINEAR && + BABL(babl->conversion.source)->class_type == BABL_MODEL) + { + Babl *src_format=NULL; + Babl *dst_format=NULL; + if (BABL(babl->conversion.source) == babl_model_id (BABL_RGBA)) + { + src_format = babl_format_id (BABL_RGBA_DOUBLE); + dst_format = babl_format_with_model_as_type ( + BABL(babl->conversion.destination), + babl_type_id (BABL_DOUBLE)); + } + else if (BABL(babl->conversion.destination) == babl_model_id (BABL_RGBA)) + { + src_format = babl_format_with_model_as_type ( + BABL(babl->conversion.source), + babl_type_id (BABL_DOUBLE)); + dst_format = babl_format_id (BABL_RGBA_DOUBLE); + } + else + { + babl_fatal ("neither source nor destination model is RGBA (requirement might be temporary)"); + } + babl_conversion_new ( + src_format, + dst_format, + "linear", linear, + NULL); + babl->conversion.error = 0.0; + } + return babl; } static char buf[512]=""; static char * -create_name (Babl *source, Babl *destination) +create_name (Babl *source, Babl *destination, int type) { if (babl_extender ()) { - snprintf (buf, 512-1, "%s : %s to %s", BABL(babl_extender())->instance.name, source->instance.name, destination->instance.name); + snprintf (buf, 512-1, "%s : %s%s to %s", + BABL(babl_extender())->instance.name, + type == BABL_CONVERSION_LINEAR?"": + type == BABL_CONVERSION_PLANE?"plane ": + type == BABL_CONVERSION_PLANAR?"planar ":"Eeeek! ", + source->instance.name, + destination->instance.name); buf[511]='\0'; } else { - snprintf (buf, 512-1, "%s to %s", source->instance.name, destination->instance.name); + snprintf (buf, 512-1, "%s %s to %s", + type == BABL_CONVERSION_LINEAR?"": + type == BABL_CONVERSION_PLANE?"plane ": + type == BABL_CONVERSION_PLANAR?"planar ":"Eeeek! ", + source->instance.name, + destination->instance.name); buf[511]='\0'; } return buf; @@ -129,7 +180,7 @@ babl_conversion_new (void *first_arg, BablFuncLinear linear = NULL; BablFuncPlane plane = NULL; BablFuncPlanar planar = NULL; - + int type = 0; int got_func = 0; const char *arg = first_arg; @@ -144,6 +195,7 @@ babl_conversion_new (void *first_arg, assert (BABL_IS_BABL(source)); assert (BABL_IS_BABL(destination)); + while (arg) { @@ -192,13 +244,28 @@ babl_conversion_new (void *first_arg, assert (source); assert (destination); - babl = conversion_new (create_name (source, destination), + if (linear) + { + type = BABL_CONVERSION_LINEAR; + } + else if (plane) + { + type = BABL_CONVERSION_PLANE; + } + else if (planar) + { + type = BABL_CONVERSION_PLANAR; + } + babl = conversion_new (create_name (source, destination, type), id, source, destination, linear, plane, planar); { Babl *ret = babl_db_insert (db, babl); if (ret!=babl) babl_free (babl); + else + babl_add_ptr_to_list ((void ***)&(source->type.from), babl); + return ret; } } @@ -252,11 +319,13 @@ babl_conversion_planar_process (BablConversion *conversion, } long -babl_conversion_process (BablConversion *conversion, - void *source, - void *destination, - long n) +babl_conversion_process (Babl *babl, + void *source, + void *destination, + long n) { + BablConversion *conversion = (BablConversion*) babl; + babl_assert (BABL_IS_BABL (conversion)); switch (BABL(conversion)->class_type) @@ -309,8 +378,10 @@ babl_conversion_process (BablConversion *conversion, n); break; case BABL_CONVERSION_LINEAR: - babl_assert (!BABL_IS_BABL (source)); - babl_assert (!BABL_IS_BABL (destination)); + /* the assertions relied on a babl_malloc structure + * + * babl_assert (!BABL_IS_BABL (source)); + babl_assert (!BABL_IS_BABL (destination));*/ babl_conversion_linear_process (conversion, source, @@ -325,7 +396,136 @@ babl_conversion_process (BablConversion *conversion, return 0; break; } + + conversion->processings ++; + conversion->pixels += n; return n; } +#define pixels 8192*2 + +static double * +test_create (void) +{ + double *test; + int i; + + srandom (20050728); + + test = babl_malloc (sizeof (double) * pixels * 4); + + for (i = 0; i < pixels * 4; i++) + test [i] = (double) random () / RAND_MAX; + + return test; +} + +double +babl_conversion_error (BablConversion *conversion) +{ + Babl *fmt_source; + Babl *fmt_destination; + + Babl *fmt_rgba_double; + + double error = 0.0; + unsigned int ticks_start = 0; + unsigned int ticks_end = 0; + + double *test; + void *source; + void *destination; + double *destination_rgba_double; + void *ref_destination; + double *ref_destination_rgba_double; + + + if (!conversion) + return 0.0; + + fmt_source = BABL(conversion->source); + fmt_destination = BABL(conversion->destination); + + if (fmt_source == fmt_destination) + { + conversion->error = 0.0; + return 0.0; + } + + if (!(fmt_source->instance.id != BABL_RGBA && + fmt_destination->instance.id != BABL_RGBA && + fmt_source->instance.id != BABL_DOUBLE && + fmt_destination->instance.id != BABL_DOUBLE && + fmt_source->class_type == BABL_FORMAT && + fmt_destination->class_type == BABL_FORMAT)) + { + conversion->error = 0.000042; + } + if (conversion->error != -1.0) /* double conversion against a set value should work */ + { + return conversion->error; + } + + test=test_create (); + + fmt_rgba_double = babl_format_new ( + babl_model ("RGBA"), + babl_type ("double"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + + + source = babl_calloc (pixels, fmt_source->format.bytes_per_pixel); + destination = babl_calloc (pixels, fmt_destination->format.bytes_per_pixel); + ref_destination = babl_calloc (pixels, fmt_destination->format.bytes_per_pixel); + destination_rgba_double = babl_calloc (pixels, fmt_rgba_double->format.bytes_per_pixel); + ref_destination_rgba_double = babl_calloc (pixels, fmt_rgba_double->format.bytes_per_pixel); + + babl_process (babl_fish_reference (fmt_rgba_double, fmt_source), + test, source, pixels); + + ticks_start = babl_ticks (); + babl_process (babl_fish_simple (conversion), + source, destination, pixels); + ticks_end = babl_ticks (); + + babl_process (babl_fish_reference (fmt_source, fmt_destination), + source, ref_destination, pixels); + + babl_process (babl_fish_reference (fmt_destination, fmt_rgba_double), + ref_destination, ref_destination_rgba_double, pixels); + babl_process (babl_fish_reference (fmt_destination, fmt_rgba_double), + destination, destination_rgba_double, pixels); + + { + int i; + + for (i=0;ierror = error; + conversion->cost = ticks_end-ticks_start; + + return error; +} + + BABL_CLASS_TEMPLATE (conversion) diff --git a/babl/babl-core.c b/babl/babl-core.c index bcc54f9..e79a0fd 100644 --- a/babl/babl-core.c +++ b/babl/babl-core.c @@ -44,6 +44,7 @@ convert_double_double (void *src, return n; } +/* static long copy_strip_1 (int src_bands, void **src, @@ -73,6 +74,16 @@ copy_strip_1 (int src_bands, return n; } + +*/ +static long +rgba_to_rgba (void *src, + void *dst, + long n) +{ + memcpy (dst, src, n * sizeof (double) * 4); + return n; +} void babl_core_init (void) { @@ -82,13 +93,6 @@ babl_core_init (void) "bits", 64, NULL); - babl_conversion_new ( - babl_type_id (BABL_DOUBLE), - babl_type_id (BABL_DOUBLE), - "plane", convert_double_double, - NULL - ); - babl_component_new ( "R", "id", BABL_RED, @@ -124,10 +128,36 @@ babl_core_init (void) babl_component_id (BABL_ALPHA), NULL); + babl_format_new ( + "id", BABL_RGBA_DOUBLE, + babl_model_id (BABL_RGBA), + babl_type_id (BABL_DOUBLE), + babl_component_id (BABL_RED), + babl_component_id (BABL_GREEN), + babl_component_id (BABL_BLUE), + babl_component_id (BABL_ALPHA), + NULL); + + /* babl_conversion_new ( babl_model_id (BABL_RGBA), babl_model_id (BABL_RGBA), "planar", copy_strip_1, NULL ); + */ + + babl_conversion_new ( + babl_type_id (BABL_DOUBLE), + babl_type_id (BABL_DOUBLE), + "plane", convert_double_double, + NULL + ); + + babl_conversion_new ( + babl_model_id (BABL_RGBA), + babl_model_id (BABL_RGBA), + "linear", rgba_to_rgba, + NULL + ); } diff --git a/babl/babl-db.c b/babl/babl-db.c index 1294e1a..3e70900 100644 --- a/babl/babl-db.c +++ b/babl/babl-db.c @@ -75,6 +75,13 @@ babl_db_init(void) return db; } + +int +babl_db_count (BablDb *db) +{ + return db->count; +} + void babl_db_destroy (BablDb *db) { diff --git a/babl/babl-db.h b/babl/babl-db.h index caa6866..f7e9784 100644 --- a/babl/babl-db.h +++ b/babl/babl-db.h @@ -31,6 +31,7 @@ void babl_db_destroy (BablDb *db); void babl_db_each (BablDb *db, BablEachFunction each_fun, void *user_data); +int babl_db_count (BablDb *db); Babl * babl_db_insert (BablDb *db, Babl *entry); Babl * babl_db_exist (BablDb *db, diff --git a/babl/babl-fish-path.c b/babl/babl-fish-path.c new file mode 100644 index 0000000..491ac6f --- /dev/null +++ b/babl/babl-fish-path.c @@ -0,0 +1,420 @@ +/* babl - dynamically extendable universal pixel fish library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "babl-internal.h" + +#define BABL_LEGAL_ERROR 0.000001 + +typedef struct BablChainContext { + Babl *from; + Babl *to; + + double *best_cost; + double *best_loss; + + Babl **chain; + int *conversions; + + Babl **temp_chain; + int temp_conversions; + + int max_conversions; +} BablChainContext; + +static int +format_has_alpha (Babl *babl) +{ + int i; + for (i=0; iformat.components; i++) + if (babl->format.component[i]->instance.id == BABL_ALPHA) + return 1; + return 0; +} + +static int +format_analytic_loss (Babl *source, + Babl *destination) +{ + int loss = 0; + + if (source->format.components < + destination->format.components) + { + loss |= 8; + } + + if ( format_has_alpha (source) && + !format_has_alpha (destination)) + { + loss |= 4; + } + + if ( BABL(source->format.type[0])->type.bits > + BABL(destination->format.type[0])->type.bits) + { + loss |= 2; + } + + if ( source->format.bytes_per_pixel > + destination->format.bytes_per_pixel) + { + loss |= 1; + } + + + + + return loss; +} + + +static int +chain_gen_each (Babl *babl, + void *userdata); + +static int +get_conversion_chain (Babl *from, + Babl *to, + + double *best_cost, + double *best_loss, + Babl **chain, + int *conversions, + + Babl **temp_chain, + int temp_conversions, + + int max_conversions) +{ + BablChainContext context; + + if (temp_conversions>=max_conversions) + return 0; + + if (temp_conversions == 0) + { + /* chain initialization */ + *conversions = 0; + *best_cost = 200000.0; + *best_loss = 200000.0; + chain[0] = NULL; + temp_chain[0] = NULL; + + /* Bail out if requesting something stupid (to and from same format, an + * optimized memcpy should be used instead (assuming linear buffers). + */ + + if (from == to) + return 0; + } + + /* copy parameters to stack */ + context.from = from; + context.to = to; + + context.best_cost = best_cost; + context.best_loss = best_loss; + context.chain = chain; + context.conversions = conversions; + + context.temp_chain = temp_chain; + context.temp_conversions = temp_conversions; + + context.max_conversions = max_conversions; + + if (temp_conversions == 0) + { + temp_chain[temp_conversions]=NULL; + babl_assert (from); + babl_assert (from->class_type == BABL_FORMAT); + if (!from->format.from) + return 0; + + babl_list_each ((void**) from->format.from, + chain_gen_each, + &context); + } + else + { + if (BABL(temp_chain[temp_conversions-1]) && + BABL(temp_chain[temp_conversions-1]->conversion.destination)-> + format.from) + + babl_list_each ( + (void **) + BABL(temp_chain[temp_conversions-1]->conversion.destination)-> + format.from, + chain_gen_each, + &context); + } + + return 0; +} + +static int +chain_gen_each (Babl *babl, + void *userdata) +{ + BablChainContext *c = userdata; + + /* fill in the conversion for the chain index we are at */ + c->temp_chain[c->temp_conversions] = babl; + + { + if (BABL(babl->conversion.destination) == c->to) + { + /* a candidate path has been found */ + + double temp_cost = 0.0; + double temp_loss = 0.0; + double error = 1.0; + int analytic_loss = 0; + int i; + + for (i=0; i < c->temp_conversions+1; i++) + { + error *= (1.0+c->temp_chain[i]->conversion.error); + temp_cost += c->temp_chain[i]->conversion.cost; + analytic_loss |= format_analytic_loss ( + BABL(c->temp_chain[i]->conversion.source), + BABL(c->temp_chain[i]->conversion.destination)); + } + temp_loss = analytic_loss; + + if (error <= (1.0 + BABL_LEGAL_ERROR) /* we're legal */ && + + /* better than the existing best candidate */ + ( temp_loss < *c->best_loss || + (temp_loss == *c->best_loss && + temp_cost < *c->best_cost))) + { + int i; + + *c->best_cost = temp_cost; + *c->best_loss = temp_loss; + *c->conversions = c->temp_conversions + 1; + + /* copy from temp chain to best chain */ + for (i = 0.0; i < *c->conversions; i++) + c->chain[i] = c->temp_chain[i]; + } + } + else + { + /* try to add another conversion level in chain,.. */ + get_conversion_chain (c->from, /* irrelevant when recalled */ + c->to, + + c->best_cost, + c->best_loss, + c->chain, + c->conversions, + + c->temp_chain, + c->temp_conversions + 1, + + c->max_conversions); + } + } + return 0; +} + +static inline Babl * +assert_conversion_find (void *source, + void *destination) +{ + int i=0; + Babl **conversion; + + conversion = (void*)BABL(source)->type.from; + while (conversion && conversion[i]) + { + if (conversion[i]->conversion.destination == destination) + return (Babl*)conversion[i]; + i++; + } + babl_fatal ("failed, aborting"); + return NULL; +} + +static char buf[1024]; +static char * +create_name (Babl *source, + Babl *destination, + int is_reference) +{ + /* fish names are intentionally kept short */ + snprintf (buf, 1024, "%s %p %p", "", + source, destination); + return buf; +} + +Babl * +babl_fish_path (Babl *source, + Babl *destination) +{ + Babl *babl = NULL; + char *name = create_name (source, destination, 1); + Babl *temp_chain[BABL_MAX_PATH_LENGTH]; + + babl_assert (BABL_IS_BABL (source)); + babl_assert (BABL_IS_BABL (destination)); + + babl_assert (source->class_type == BABL_FORMAT); + babl_assert (destination->class_type == BABL_FORMAT); + + babl = babl_calloc (1, sizeof (BablFishPath) + + strlen (name) + 1); + babl->class_type = BABL_FISH_PATH; + babl->instance.id = 0; + babl->instance.name = ((void *)babl) + sizeof(BablFishPath); + strcpy (babl->instance.name, name); + babl->fish.source = (union Babl*)source; + babl->fish.destination = (union Babl*)destination; + + babl->fish.processings = 0; + babl->fish.pixels = 0; + + babl->fish_path.cost = 200000; + babl->fish_path.loss = 200000; + babl->fish_path.conversions = 0; + babl->fish_path.conversion[0] = NULL; + + babl_assert (source->class_type == BABL_FORMAT); + babl_assert (destination->class_type == BABL_FORMAT); + + get_conversion_chain (source, + destination, + &babl->fish_path.cost, + &babl->fish_path.loss, + (Babl**)(babl->fish_path.conversion), + &babl->fish_path.conversions, + temp_chain, + 0, + BABL_MAX_PATH_LENGTH); + if (babl->fish_path.conversions==0) + { + babl_free (babl); + return NULL; + } + + { + Babl *ret = babl_db_insert (babl_fish_db (), babl); + if (ret!=babl) + babl_free (babl); + return ret; + } +} + +static long +chain_process (BablConversion *chain[], + int conversions, + void *source, + void *destination, + long n) +{ + void *bufA = NULL; + void *bufB = NULL; + int i; + + babl_assert (source); + babl_assert (destination); + + if (conversions > 1) + bufA = babl_malloc (n * sizeof (double) * 5); + if (conversions > 2) + bufB = babl_malloc (n * sizeof (double) * 5); + + for (i=0; ifish.source)->instance.name, + BABL(babl->fish.destination)->instance.name); + + for (i=0; i< babl->fish_path.conversions; i++) + babl_log ("\t%s\n", + BABL(babl->fish_path.conversion[i])->instance.name); +*/ + + return chain_process (babl->fish_path.conversion, + babl->fish_path.conversions, + source, + destination, + n); +} + diff --git a/babl/babl-fish-reference.c b/babl/babl-fish-reference.c new file mode 100644 index 0000000..91acfbc --- /dev/null +++ b/babl/babl-fish-reference.c @@ -0,0 +1,338 @@ +/* babl - dynamically extendable universal pixel fish library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "babl-internal.h" + +static Babl * +assert_conversion_find (void *source, + void *destination) +{ + Babl *ret = babl_conversion_find (source, destination); + + if (!ret) + babl_fatal ("failed, aborting"); + return ret; +} + +static char buf[1024]; +static char * +create_name (Babl *source, + Babl *destination, + int is_reference) +{ + /* fish names are intentionally kept short */ + snprintf (buf, 1024, "%s %p %p", + is_reference?"ref " + :"", + source, destination); + return buf; +} + + +Babl * +babl_fish_reference (Babl *source, + Babl *destination) +{ + Babl *babl = NULL; + char *name = create_name (source, destination, 1); + + babl_assert (BABL_IS_BABL (source)); + babl_assert (BABL_IS_BABL (destination)); + + babl_assert (source->class_type == BABL_FORMAT); + babl_assert (destination->class_type == BABL_FORMAT); + + babl = babl_malloc (sizeof (BablFishReference) + + strlen (name) + 1); + babl->class_type = BABL_FISH_REFERENCE; + babl->instance.id = 0; + babl->instance.name = ((void *)babl) + sizeof(BablFishReference); + strcpy (babl->instance.name, name); + babl->fish.source = (union Babl*)source; + babl->fish.destination = (union Babl*)destination; + + babl->fish.processings = 0; + babl->fish.pixels = 0; + + { + Babl *ret = babl_db_insert (babl_fish_db (), babl); + if (ret!=babl) + babl_free (babl); + return ret; + } +} + + +static void +convert_to_double (BablFormat *source_fmt, + BablImage *source, + void *source_buf, + void *source_double_buf, + int n) +{ + int i; + + BablImage *src_img; + BablImage *dst_img; + + src_img = (BablImage*) babl_image ( + babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL); + dst_img = (BablImage*) babl_image ( + babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL); + + dst_img->type[0] = (BablType*) babl_type_id (BABL_DOUBLE); + dst_img->pitch[0] = + (dst_img->type[0]->bits/8) * source_fmt->model->components; + dst_img->stride[0] = 0; + + + src_img->data[0] = source_buf; + src_img->type[0] = (BablType*) babl_type_id (BABL_DOUBLE); + src_img->pitch[0] = source_fmt->bytes_per_pixel; + src_img->stride[0] = 0; + + /* i is source position */ + for (i=0 ; icomponents; i++) + { + int j; + + src_img->type[0] = source_fmt->type[i]; + /* j is source position */ + for (j=0;jmodel->components;j++) + { + if (source_fmt->component[i] == + source_fmt->model->component[j]) + { + dst_img->data[0] = + source_double_buf + (dst_img->type[0]->bits/8) * j; + break; + } + } + + babl_process ( + assert_conversion_find (src_img->type[0], dst_img->type[0]), + src_img, dst_img, + n); + src_img->data[0] += src_img->type[0]->bits/8; + } + babl_free (src_img); + babl_free (dst_img); +} + + +static void +convert_from_double (BablFormat *destination_fmt, + void *destination_double_buf, + BablImage *destination, + void *destination_buf, + int n) +{ + int i; + + BablImage *src_img; + BablImage *dst_img; + + src_img = (BablImage*) babl_image ( + babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL); + dst_img = (BablImage*) babl_image ( + babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL); + + src_img->type[0] = (BablType*) babl_type_id (BABL_DOUBLE); + src_img->pitch[0] = (src_img->type[0]->bits/8) * destination_fmt->model->components; + src_img->stride[0] = 0; + + dst_img->data[0] = destination_buf; + dst_img->type[0] = (BablType*) babl_type_id (BABL_DOUBLE); + dst_img->pitch[0] = destination_fmt->bytes_per_pixel; + dst_img->stride = 0; + + for (i=0 ; icomponents; i++) + { + int j; + + dst_img->type[0] = destination_fmt->type[i]; + + for (j=0;jmodel->components;j++) + { + if (destination_fmt->component[i] == + destination_fmt->model->component[j]) + { + src_img->data[0] = + destination_double_buf + (src_img->type[0]->bits/8) * j; + break; + } + } + + babl_process ( + assert_conversion_find (src_img->type[0], dst_img->type[0]), + src_img, dst_img, + n); + dst_img->data[0] += dst_img->type[0]->bits/8; + } + babl_free (src_img); + babl_free (dst_img); +} + + +static int +process_same_model (Babl *babl, + BablImage *source, + BablImage *destination, + long n) +{ + void *double_buf; + + if (BABL_IS_BABL (source) || + BABL_IS_BABL (destination)) + { + babl_log ("args=(%p, %p, %p, %li): trying to handle BablImage (unconfirmed code)", + babl_fish, source, destination, n); + } + + double_buf = babl_malloc(sizeof (double) * n * + BABL(babl->fish.source)->format.model->components); + + convert_to_double ( + (BablFormat*) BABL(babl->fish.source), + BABL_IS_BABL(source)?source:NULL, + BABL_IS_BABL(source)?NULL:source, + double_buf, + n + ); + + convert_from_double ( + (BablFormat*) BABL(babl->fish.destination), + double_buf, + BABL_IS_BABL(destination)?destination:NULL, + BABL_IS_BABL(destination)?NULL:destination, + n + ); + + babl_free (double_buf); + return 0; +} + +long +babl_fish_reference_process (Babl *babl, + BablImage *source, + BablImage *destination, + long n) +{ + void *source_double_buf; + void *rgba_double_buf; + void *destination_double_buf; + Babl *source_image; + Babl *rgba_image; + Babl *destination_image; + + if (BABL(babl->fish.source)->format.model == + BABL(babl->fish.destination)->format.model) + return process_same_model (babl, source, destination, n); + + if (BABL_IS_BABL (source) || + BABL_IS_BABL (destination)) + { + babl_log ("args=(%p, %p, %p, %li): trying to handle BablImage (unconfirmed code)", + babl_fish, source, destination, n); + } + + source_double_buf = babl_malloc(sizeof (double) * n * + BABL(babl->fish.source)->format.model->components); + rgba_double_buf = babl_malloc(sizeof (double) * n * 4); + destination_double_buf = babl_malloc(sizeof (double) * n * + BABL(babl->fish.destination)->format.model->components); + + source_image = babl_image_from_linear ( + source_double_buf,BABL(BABL((babl->fish.source)) -> format.model)); + rgba_image = babl_image_from_linear ( + rgba_double_buf, babl_model_id (BABL_RGBA)); + destination_image = babl_image_from_linear ( + destination_double_buf, BABL(BABL((babl->fish.destination))->format.model)); + + convert_to_double ( + (BablFormat*) BABL(babl->fish.source), + BABL_IS_BABL(source)?source:NULL, + BABL_IS_BABL(source)?NULL:source, + source_double_buf, + n + ); + + { + Babl *conv = + assert_conversion_find ( + BABL(babl->fish.source)->format.model, + babl_model_id (BABL_RGBA) + ); + if (conv->class_type == BABL_CONVERSION_PLANAR) + { + babl_process ( + conv, + source_image, rgba_image, + n); + } + else if (conv->class_type == BABL_CONVERSION_LINEAR) + { + babl_process ( + conv, + source_double_buf, rgba_double_buf, + n); + } + else babl_fatal ("oops"); + } + + { + Babl *conv = + assert_conversion_find ( + babl_model_id (BABL_RGBA), + BABL(babl->fish.destination)->format.model); + if (conv->class_type == BABL_CONVERSION_PLANAR) + { + babl_process ( + conv, + rgba_image, destination_image, + n); + } + else if (conv->class_type == BABL_CONVERSION_LINEAR) + { + babl_process ( + conv, + rgba_double_buf, destination_double_buf, + n); + } + else babl_fatal ("oops"); + } + + convert_from_double ( + (BablFormat*) BABL(babl->fish.destination), + destination_double_buf, + BABL_IS_BABL(destination)?destination:NULL, + BABL_IS_BABL(destination)?NULL:destination, + n + ); + + babl_free (source_image); + babl_free (rgba_image); + babl_free (destination_image); + + babl_free (destination_double_buf); + babl_free (rgba_double_buf); + babl_free (source_double_buf); + return n; +} + diff --git a/babl/babl-fish-simple.c b/babl/babl-fish-simple.c new file mode 100644 index 0000000..dc9d62e --- /dev/null +++ b/babl/babl-fish-simple.c @@ -0,0 +1,57 @@ +/* babl - dynamically extendable universal pixel fish library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "babl-internal.h" + +static char * +create_name (BablConversion *conversion) +{ + return conversion->instance.name; +} + +Babl * +babl_fish_simple (BablConversion *conversion) +{ + Babl *babl = NULL; + char *name; + + babl_assert (BABL_IS_BABL (conversion)); + + name = create_name (conversion); + + babl = babl_malloc (sizeof (BablFishSimple) + + strlen (name) + 1); + babl->class_type = BABL_FISH_SIMPLE; + babl->instance.id = 0; + babl->instance.name = ((void *)babl) + sizeof(BablFishSimple); + strcpy (babl->instance.name, name); + babl->fish.source = (union Babl*)conversion->source; + babl->fish.destination = (union Babl*)conversion->destination; + + babl->fish.processings = 0; + babl->fish.pixels = 0; + babl->fish_simple.conversion = conversion; + + { + Babl *ret = babl_db_insert (babl_fish_db (), babl); + if (ret!=babl) + babl_free (babl); + return ret; + } +} diff --git a/babl/babl-fish.c b/babl/babl-fish.c index 2dd6a73..50737f3 100644 --- a/babl/babl-fish.c +++ b/babl/babl-fish.c @@ -18,150 +18,48 @@ */ #include "babl-internal.h" -#include "babl-db.h" #include #include -/*#include "babl-type.h" -#include "babl-model.h" -#include "babl-image.h" -#include "babl-component.h" -#include "babl-format.h"*/ -static int -each_babl_fish_destroy (Babl *babl, - void *data) -{ - babl_free (babl); - return 0; /* continue iterating */ -} - -static char buf[1024]; -static char * -create_name (Babl *source, - Babl *destination, - int is_reference) -{ - /* fish names are intentionally kept short */ - snprintf (buf, 1024, "%s %p %p", - is_reference?"ref " - :"", - source, destination); - return buf; -} - -typedef struct SearchData -{ - Babl *source; - Babl *destination; - BablConversion *result; -} SearchData; - -Babl *babl_conversion_find2 (void *source, - void *destination) -{ - int i=0; - Babl **conversion; - - conversion = (void*)BABL(source)->type.from; - while (conversion && conversion[i]) - { - if (conversion[i]->conversion.destination == destination) - return (Babl*)conversion[i]; - i++; - } - babl_fatal ("failed, aborting"); - return NULL; -} - - -Babl *babl_conversion_find (void *source, - void *destination) +static int +match_conversion (Babl *conversion, + void *inout) { - int i=0; - Babl **conversion; + void **data = inout; - conversion = (void*)BABL(source)->type.from; - while (conversion && conversion[i]) + if ((Babl *) conversion->conversion.destination == (Babl*) *data) { - if (conversion[i]->conversion.destination == destination) - return (Babl*)conversion[i]; - i++; + *data = (void *)conversion; + return 1; } - return NULL; + return 0; } - - Babl * -babl_fish_reference (Babl *source, - Babl *destination) +babl_conversion_find (void *source, + void *destination) { - Babl *babl = NULL; - char *name = create_name (source, destination, 1); - - babl_assert (BABL_IS_BABL (source)); - babl_assert (BABL_IS_BABL (destination)); - - babl_assert (source->class_type == BABL_FORMAT); - babl_assert (destination->class_type == BABL_FORMAT); + void *data=destination; - babl = babl_malloc (sizeof (BablFishReference) + - strlen (name) + 1); - babl->class_type = BABL_FISH_REFERENCE; - babl->instance.id = 0; - babl->instance.name = ((void *)babl) + sizeof(BablFishReference); - strcpy (babl->instance.name, name); - babl->fish.source = (union Babl*)source; - babl->fish.destination = (union Babl*)destination; - - babl->fish.processings = 0; - babl->fish.pixels = 0; - - { - Babl *ret = babl_db_insert (db, babl); - if (ret!=babl) - babl_free (babl); - return ret; - } + babl_list_each ((void*)BABL(source)->type.from, match_conversion, &data); + if (data == destination) + return NULL; + return data; } -Babl * -babl_fish_simple (BablConversion *conversion) +BablDb * +babl_fish_db (void) { - Babl *babl = NULL; - char *name; - - babl_assert (BABL_IS_BABL (conversion)); - - name = create_name (BABL(conversion->source), - BABL(conversion->destination), - 0); - - babl = babl_malloc (sizeof (BablFishSimple) + - strlen (name) + 1); - babl->class_type = BABL_FISH_SIMPLE; - babl->instance.id = 0; - babl->instance.name = ((void *)babl) + sizeof(BablFishSimple); - strcpy (babl->instance.name, name); - babl->fish.source = (union Babl*)conversion->source; - babl->fish.destination = (union Babl*)conversion->destination; - - babl->fish.processings = 0; - babl->fish.pixels = 0; - babl->fish_simple.conversion = conversion; - - { - Babl *ret = babl_db_insert (db, babl); - if (ret!=babl) - babl_free (babl); - return ret; - } + if (!db) + db = babl_db_init (); + return db; } Babl * babl_fish (void *source, - void *destination) + void *destination, + ...) { Babl *source_format = NULL; Babl *destination_format = NULL; @@ -202,259 +100,103 @@ babl_fish (void *source, } - { - Babl *shortcut_conversion = babl_conversion_find (source_format, destination_format); + if (0) + { + Babl *shortcut_conversion; + + shortcut_conversion = babl_conversion_find ( + source_format, destination_format); if (shortcut_conversion) { return babl_fish_simple (&(shortcut_conversion->conversion)); } } - return babl_fish_reference (source_format, destination_format); -} - - -static void -convert_to_double (BablFormat *source_fmt, - BablImage *source, - void *source_buf, - void *source_double_buf, - int n) -{ - int i; - - BablImage *src_img; - BablImage *dst_img; - - src_img = (BablImage*) babl_image ( - babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL); - dst_img = (BablImage*) babl_image ( - babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL); - - dst_img->type[0] = (BablType*) babl_type_id (BABL_DOUBLE); - dst_img->pitch[0] = - (dst_img->type[0]->bits/8) * source_fmt->model->components; - dst_img->stride[0] = 0; - - - src_img->data[0] = source_buf; - src_img->type[0] = (BablType*) babl_type_id (BABL_DOUBLE); - src_img->pitch[0] = source_fmt->bytes_per_pixel; - src_img->stride[0] = 0; - - /* i is source position */ - for (i=0 ; icomponents; i++) - { - int j; - - src_img->type[0] = source_fmt->type[i]; - /* j is source position */ - for (j=0;jmodel->components;j++) - { - if (source_fmt->component[i] == - source_fmt->model->component[j]) - { - dst_img->data[0] = - source_double_buf + (dst_img->type[0]->bits/8) * j; - break; - } - } - - babl_process ( - babl_conversion_find2 (src_img->type[0], dst_img->type[0]), - src_img, dst_img, - n); - src_img->data[0] += src_img->type[0]->bits/8; - } - babl_free (src_img); - babl_free (dst_img); -} - - -static void -convert_from_double (BablFormat *destination_fmt, - void *destination_double_buf, - BablImage *destination, - void *destination_buf, - int n) -{ - int i; - - BablImage *src_img; - BablImage *dst_img; - - src_img = (BablImage*) babl_image ( - babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL); - dst_img = (BablImage*) babl_image ( - babl_component_id (BABL_LUMINANCE), NULL, 1, 0, NULL); - - src_img->type[0] = (BablType*) babl_type_id (BABL_DOUBLE); - src_img->pitch[0] = - (src_img->type[0]->bits/8) * destination_fmt->model->components; - src_img->stride[0] = 0; - - dst_img->data[0] = destination_buf; - dst_img->type[0] = (BablType*) babl_type_id (BABL_DOUBLE); - dst_img->pitch[0] = destination_fmt->bytes_per_pixel; - dst_img->stride = 0; - - for (i=0 ; icomponents; i++) - { - int j; - - dst_img->type[0] = destination_fmt->type[i]; - - for (j=0;jmodel->components;j++) - { - if (destination_fmt->component[i] == - destination_fmt->model->component[j]) - { - src_img->data[0] = - destination_double_buf + (src_img->type[0]->bits/8) * j; - break; - } - } - babl_process ( - babl_conversion_find2 (src_img->type[0], dst_img->type[0]), - src_img, dst_img, - n); - dst_img->data[0] += dst_img->type[0]->bits/8; - } - babl_free (src_img); - babl_free (dst_img); -} + { + Babl *fish_path; + + fish_path = babl_fish_path (source_format, destination_format); -static int -process_same_model (Babl *babl, - BablImage *source, - BablImage *destination, - long n) -{ - void *double_buf; - - if (BABL_IS_BABL (source) || - BABL_IS_BABL (destination)) - { - babl_log ("args=(%p, %p, %p, %li): trying to handle BablImage (unconfirmed code)", - babl_fish, source, destination, n); - } - - double_buf = babl_malloc(sizeof (double) * n * - BABL(babl->fish.source)->format.model->components); - - convert_to_double ( - (BablFormat*) BABL(babl->fish.source), - BABL_IS_BABL(source)?source:NULL, - BABL_IS_BABL(source)?NULL:source, - double_buf, - n - ); - - convert_from_double ( - (BablFormat*) BABL(babl->fish.destination), - double_buf, - BABL_IS_BABL(destination)?destination:NULL, - BABL_IS_BABL(destination)?NULL:destination, - n - ); + if (fish_path) + { + return fish_path; + } + } - babl_free (double_buf); - return 0; + return babl_fish_reference (source_format, destination_format); } -int -babl_fish_reference_process (Babl *babl, - BablImage *source, - BablImage *destination, - long n) +long +babl_fish_process (Babl *babl, + void *source, + void *destination, + long n) { - void *source_double_buf; - void *rgba_double_buf; - void *destination_double_buf; - Babl *source_image; - Babl *rgba_image; - Babl *destination_image; + BablImage *source_image = NULL; + BablImage *destination_image = NULL; + long ret=0; - if (BABL(babl->fish.source)->format.model == - BABL(babl->fish.destination)->format.model) - return process_same_model (babl, source, destination, n); - - if (BABL_IS_BABL (source) || - BABL_IS_BABL (destination)) + switch (babl->class_type) { - babl_log ("args=(%p, %p, %p, %li): trying to handle BablImage (unconfirmed code)", - babl_fish, source, destination, n); + case BABL_FISH_REFERENCE: + case BABL_FISH_SIMPLE: + case BABL_FISH_PATH: + + if (BABL_IS_BABL (source)) + source_image = source; + if (!source_image) + source_image = (BablImage*) babl_image_from_linear ( + source, (Babl*)babl->fish.source); + if (BABL_IS_BABL (destination)) + destination_image = destination; + if (!destination_image) + destination_image = (BablImage*) babl_image_from_linear ( + destination, (Babl*)babl->fish.destination); + + if (babl->class_type == BABL_FISH_REFERENCE) + { + ret = babl_fish_reference_process (babl, source, destination, n); + } + else if (babl->class_type == BABL_FISH_PATH) + { + ret = babl_fish_path_process (babl, source, destination, n); + } + else if (babl->class_type == BABL_FISH_SIMPLE) + { + if (BABL(babl->fish_simple.conversion)->class_type==BABL_CONVERSION_LINEAR) + { + ret = babl_conversion_process (BABL(babl->fish_simple.conversion), + source, destination, n); + } + else + { + ret = babl_conversion_process (BABL(babl->fish_simple.conversion), + source_image, destination_image, n); + } + } + + babl_free (source_image); + babl_free (destination_image); + break; + default: + babl_log ("NYI"); + ret = -1; + break; } - source_double_buf = babl_malloc(sizeof (double) * n * - BABL(babl->fish.source)->format.model->components); - rgba_double_buf = babl_malloc(sizeof (double) * n * 4); - destination_double_buf = babl_malloc(sizeof (double) * n * - BABL(babl->fish.destination)->format.model->components); - - source_image = babl_image_from_linear ( - source_double_buf,BABL(BABL((babl->fish.source)) -> format.model)); - rgba_image = babl_image_from_linear ( - rgba_double_buf, babl_model_id (BABL_RGBA)); - destination_image = babl_image_from_linear ( - destination_double_buf, BABL(BABL((babl->fish.destination))->format.model)); - - convert_to_double ( - (BablFormat*) BABL(babl->fish.source), - BABL_IS_BABL(source)?source:NULL, - BABL_IS_BABL(source)?NULL:source, - source_double_buf, - n - ); - - babl_process ( - babl_conversion_find2 ( - BABL(babl->fish.source)->format.model, - babl_model_id (BABL_RGBA) - ), - source_image, rgba_image, - n); - - babl_process ( - babl_conversion_find2 ( - babl_model_id (BABL_RGBA), - BABL(babl->fish.destination)->format.model - ), - rgba_image, destination_image, - n); - - convert_from_double ( - (BablFormat*) BABL(babl->fish.destination), - destination_double_buf, - BABL_IS_BABL(destination)?destination:NULL, - BABL_IS_BABL(destination)?NULL:destination, - n - ); - - babl_free (source_image); - babl_free (rgba_image); - babl_free (destination_image); - - babl_free (destination_double_buf); - babl_free (rgba_double_buf); - babl_free (source_double_buf); - return 0; + return ret; } -int -babl_fish_process (Babl *babl, - void *source, - void *destination, - long n) +static int +each_babl_fish_destroy (Babl *babl, + void *data) { - babl_log ("NYI"); - return -1; + babl_free (babl); + return 0; /* continue iterating */ } - - BABL_DEFINE_INIT (fish) BABL_DEFINE_DESTROY (fish) BABL_DEFINE_EACH (fish) diff --git a/babl/babl-format.c b/babl/babl-format.c index 734932d..4881b04 100644 --- a/babl/babl-format.c +++ b/babl/babl-format.c @@ -19,6 +19,7 @@ #include #include +#include #include "babl-internal.h" #include "babl-db.h" @@ -186,7 +187,7 @@ babl_format_new (void *first_arg, BablType *type [BABL_MAX_COMPONENTS]; BablSampling *current_sampling = (BablSampling*) babl_sampling (1,1); - BablType *current_type = (BablType*) babl_type_id (BABL_U8); + BablType *current_type = (BablType*) babl_type_id (BABL_DOUBLE); char *name = NULL; void *arg = first_arg; @@ -240,8 +241,9 @@ babl_format_new (void *first_arg, case BABL_CONVERSION_PLANE: case BABL_CONVERSION_PLANAR: case BABL_FISH: - case BABL_FISH_SIMPLE: case BABL_FISH_REFERENCE: + case BABL_FISH_SIMPLE: + case BABL_FISH_PATH: case BABL_IMAGE: case BABL_EXTENSION: babl_log ("%s unexpected", @@ -297,4 +299,122 @@ babl_format_new (void *first_arg, } } +int +babl_formats_count (void) +{ + return babl_db_count (db); +} + + +Babl * +babl_format_with_model_as_type (Babl *model, + Babl *type) +{ + BablComponent *component[10]; + int i; + + for (i=0;imodel.components;i++) + { + component[i]= model->model.component[i]; + } + component[i]=NULL; + + return babl_format_new ( + model, + type, + component[0], + component[1], + component[2], + component[3], + component[4], + component[5], + component[6], + component[7], + component[8], + component[9], + NULL + ); +} + +#define pixels 256 + +static double * +test_create (void) +{ + double *test; + int i; + + srandom (20050728); + + test = babl_malloc (sizeof (double) * pixels * 4); + + for (i = 0; i < pixels * 4; i++) + test [i] = (double) random () / RAND_MAX; + + return test; +} + +double +babl_format_loss (Babl *babl) +{ + double loss = 0.0; + double *test; + void *original; + double *clipped; + void *destination; + double *transformed; + + Babl *ref_fmt; + Babl *fmt; + Babl *fish_to; + Babl *fish_from; + + ref_fmt = babl_format_new ( + babl_model ("RGBA"), + babl_type ("double"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + + if (babl->format.loss != -1.0) + return babl->format.loss; + + fmt = babl; + fish_to = babl_fish_reference (ref_fmt, fmt); + fish_from = babl_fish_reference (fmt, ref_fmt); + + test = test_create (); + original = babl_calloc (pixels, fmt->format.bytes_per_pixel); + clipped = babl_calloc (pixels, ref_fmt->format.bytes_per_pixel); + destination = babl_calloc (pixels, fmt->format.bytes_per_pixel); + transformed = babl_calloc (pixels, ref_fmt->format.bytes_per_pixel); + + babl_process (fish_to, test, original, pixels); + babl_process (fish_from, original, clipped, pixels); + babl_process (fish_to, clipped, destination, pixels); + babl_process (fish_from, destination, transformed, pixels); + + { + int i; + + for (i=0;iformat.loss = loss; + return loss; +} + BABL_CLASS_TEMPLATE (format) diff --git a/babl/babl-internal.c b/babl/babl-internal.c index 0cde94e..aacac8a 100644 --- a/babl/babl-internal.c +++ b/babl/babl-internal.c @@ -36,6 +36,7 @@ static const char *class_names[] = "BablFish", "BablFishReference", "BablFishSimple", + "BablFishPath", "BablImage", "BablExtenstion", "BablSky" @@ -73,10 +74,6 @@ babl_die (void) exit (-1); } -long babl_conversion_process (Babl *conversion, - void *source, - void *destination, - long n); long babl_process (Babl *babl, void *source, @@ -89,78 +86,22 @@ babl_process (Babl *babl, babl_assert (BABL_IS_BABL (babl)); babl_assert (n>0); - /* these fields are common between conversions and fishes */ - babl->fish.processings++; - babl->fish.pixels += n; - /* matches all conversion classes */ if (babl->class_type >= BABL_CONVERSION && babl->class_type <= BABL_CONVERSION_PLANAR) return babl_conversion_process (babl, source, destination, n); - if (babl->class_type == BABL_FISH) - return babl_fish_process (babl, source, destination, n); - - if (babl->class_type == BABL_FISH_REFERENCE) - { - BablImage *source_image = NULL; - BablImage *destination_image = NULL; - long ret=0; - - if (BABL_IS_BABL (source)) - source_image = source; - if (!source_image) - source_image = (BablImage*) babl_image_from_linear ( - source, (Babl*)babl->fish.source); - if (BABL_IS_BABL (destination)) - destination_image = destination; - if (!destination_image) - destination_image = (BablImage*) babl_image_from_linear ( - destination, (Babl*)babl->fish.destination); - - ret = babl_fish_reference_process (babl, source, destination, n); - - babl_free (source_image); - babl_free (destination_image); - - return ret; - } - - if (babl->class_type == BABL_FISH_SIMPLE) + if (babl->class_type == BABL_FISH || + babl->class_type == BABL_FISH_REFERENCE || + babl->class_type == BABL_FISH_PATH || + babl->class_type == BABL_FISH_SIMPLE) { - long ret=0; - BablImage *source_image = NULL; - BablImage *destination_image = NULL; - - if (BABL_IS_BABL (source)) - source_image = source; - if (!source_image) - source_image = (BablImage*) babl_image_from_linear ( - source, (Babl*)babl->fish.source); - if (BABL_IS_BABL (destination)) - destination_image = destination; - if (!destination_image) - destination_image = (BablImage*) babl_image_from_linear ( - destination, (Babl*)babl->fish.destination); - - if (BABL(babl->fish_simple.conversion)->class_type==BABL_CONVERSION_LINEAR) - { - ret = babl_conversion_process (BABL(babl->fish_simple.conversion), - source, destination, n); - } - else - { - ret = babl_conversion_process (BABL(babl->fish_simple.conversion), - source_image, destination_image, n); - } - - babl_free (source_image); - babl_free (destination_image); - - return ret; + babl->fish.processings++; + babl->fish.pixels += n; + return babl_fish_process (babl, source, destination, n); } - babl_log ("eek"); + babl_fatal ("eek"); return -1; } @@ -183,3 +124,42 @@ babl_name (Babl *babl) babl_assert (BABL_IS_BABL (babl)); return babl->instance.name; } + +static int +each_conversion (Babl *babl, + void *user_data) +{ + babl_conversion_error (&babl->conversion); + return 0; +} + +static int +each_format (Babl *babl, + void *user_data) +{ + babl_format_loss (babl); + return 0; +} + +static int +gen_type_format_for_model (Babl *type, void *userdata) +{ + babl_format_with_model_as_type (userdata, type); + return 0; +} + +static int +gen_formats_for_model (Babl *model, void *userdata) +{ + babl_type_each (gen_type_format_for_model, model); + return 0; +} + +void +babl_extension_post_load (void) +{ + babl_conversion_each (each_conversion, NULL); + babl_format_each (each_format, NULL); + babl_model_each (gen_formats_for_model, NULL); +} + diff --git a/babl/babl-internal.h b/babl/babl-internal.h index c516f62..6f0973e 100644 --- a/babl/babl-internal.h +++ b/babl/babl-internal.h @@ -24,13 +24,15 @@ #error babl-internal.h included after babl.h #endif -#define BABL_MAX_COMPONENTS 32 +#define BABL_MAX_COMPONENTS 32 +#define BABL_MAX_PATH_LENGTH 5 #include #include #include #include "assert.h" + #include "babl-classes.h" #undef _BABL_INTERNAL_H #include "babl.h" @@ -43,30 +45,57 @@ #include "babl-memory.h" -int babl_fish_process (Babl *babl, - void *source, - void *destination, - long n); -int babl_fish_reference_process (Babl *babl, - BablImage *source, - BablImage *destination, - long n); -Babl * babl_fish_reference (Babl *source, - Babl *destination); -Babl * babl_fish_simple (BablConversion *conversion); -Babl * babl_image_from_linear (void *buffer, - Babl *format); -Babl * babl_image_double_from_image (Babl *source); -void babl_die (void); -int babl_sanity (void); -Babl * babl_extension_base (void); - -Babl * babl_extender (void); -void babl_set_extender (Babl *new_extender); - -Babl * babl_extension_quiet_log (void); - -void babl_core_init (void); +Babl * babl_conversion_find (void *source, + void *destination); +double babl_conversion_error (BablConversion *conversion); +long babl_conversion_process (Babl *conversion, + void *source, + void *destination, + long n); + +Babl * babl_extension_base (void); +void babl_extension_post_load (void); + +Babl * babl_extender (void); +void babl_set_extender (Babl *new_extender); + +Babl * babl_extension_quiet_log (void); + +long babl_fish_process (Babl *babl, + void *source, + void *destination, + long n); +long babl_fish_reference_process (Babl *babl, + BablImage *source, + BablImage *destination, + long n); + +BablDb * babl_fish_db (void); +Babl * babl_fish_reference (Babl *source, + Babl *destination); +Babl * babl_fish_simple (BablConversion *conversion); +Babl * babl_fish_path (Babl *source, + Babl *destination); + +long babl_fish_path_process (Babl *babl, + void *source, + void *destination, + long n); + +double babl_format_loss (Babl *babl); +Babl * babl_image_from_linear (void *buffer, + Babl *format); +Babl * babl_image_double_from_image (Babl *source); + +double babl_model_is_symmetric (Babl *babl); +void babl_die (void); +int babl_sanity (void); + +void babl_core_init (void); +Babl * babl_format_with_model_as_type (Babl *model, + Babl *type); +int babl_formats_count (void); /* should maybe be templated? */ +int babl_type_is_symmetric (Babl *babl); /* FIXME: nasty,. including the symbol even in files where it is * not needed,. and a dummy function to use it in those cases @@ -106,6 +135,7 @@ real_babl_log (const char *file, va_end (varg); fprintf (stdout, "\n"); + fflush (0); return; hack_hack (); } @@ -158,7 +188,7 @@ babl_##type_name##_id (int id) \ babl = babl_db_exist (db, id, NULL); \ if (!babl) \ { \ - babl_log ("%s(%i): not found", __FUNCTION__, id); \ + babl_fatal ("%s(%i): not found", __FUNCTION__, id); \ } \ return babl; \ } diff --git a/babl/babl-introspect.c b/babl/babl-introspect.c index 685dbf1..ea6a4ec 100644 --- a/babl/babl-introspect.c +++ b/babl/babl-introspect.c @@ -165,6 +165,7 @@ conversion_introspect (Babl *babl) { babl_log ("\t\tprocessings:%i pixels:%li", babl->conversion.processings, babl->conversion.pixels); + babl_log ("\t\tcost: %i error: %f", babl->conversion.cost, babl->conversion.error); } static void diff --git a/babl/babl-model.c b/babl/babl-model.c index f48779e..6e5428d 100644 --- a/babl/babl-model.c +++ b/babl/babl-model.c @@ -20,6 +20,7 @@ #include "babl-internal.h" #include #include +#include #include "babl-db.h" @@ -125,8 +126,9 @@ babl_model_new (void *first_argument, case BABL_CONVERSION_PLANE: case BABL_CONVERSION_PLANAR: case BABL_FISH: - case BABL_FISH_REFERENCE: case BABL_FISH_SIMPLE: + case BABL_FISH_REFERENCE: + case BABL_FISH_PATH: case BABL_IMAGE: case BABL_EXTENSION: babl_log ("%s unexpected", babl_class_name (babl->class_type)); @@ -168,4 +170,144 @@ babl_model_new (void *first_argument, } } + +#define TOLERANCE 0.001 + +#define pixels 512 + +static double * +test_create (void) +{ + double *test; + int i; + + srandom (20050728); + + test = babl_malloc (sizeof (double) * pixels * 4); + + for (i = 0; i < pixels * 4; i++) + test [i] = ((double) random () / RAND_MAX ) * 1.4 - 0.2; + + return test; +} + +static Babl *reference_format (void) +{ + static Babl *self = NULL; + + if (!self) + self = babl_format_new ( + babl_model ("RGBA"), + babl_type ("double"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + return self; +} + +static Babl *construct_double_format (Babl *model) +{ + void *argument[42+1]; + int args = 0; + int i; + + argument[args++] = model; + argument[args++] = babl_type ("double"); + + for (i=0;imodel.components; i++) + { + argument[args++] = model->model.component[i]; + } + argument[args++] = NULL; + +#define o(argno) argument[argno], + return babl_format_new (o(0) o(1) o(2) o(3) + o(4) o(5) o(6) o(7) + o(8) o(9) o(10) o(11) + o(12) o(13) o(14) o(15) + o(16) o(17) o(18) o(19) + o(20) o(21) o(22) o(23) + o(24) o(25) o(26) o(27) + o(28) o(29) o(30) o(31) + o(32) o(33) o(34) o(35) + o(36) o(37) o(38) o(39) + o(40) o(41) o(42) NULL); +#undef o +} + +double +babl_model_is_symmetric (Babl *babl) +{ + double *test; + void *original; + double *clipped; + void *destination; + double *transformed; + int symmetric=1; + + Babl *ref_fmt; + Babl *fmt; + Babl *fish_to; + Babl *fish_from; + + test = test_create (); + ref_fmt = reference_format (); + fmt = construct_double_format (babl); + fish_to = babl_fish_reference (ref_fmt, fmt); + fish_from = babl_fish_reference (fmt, ref_fmt); + + original = babl_calloc (1,64/8 * babl->model.components * pixels); + clipped = babl_calloc (1,64/8 * 4 * pixels); + destination = babl_calloc (1,64/8 * babl->model.components * pixels); + transformed = babl_calloc (1,64/8 * 4 * pixels); + + babl_process (fish_to, test, original, pixels); + babl_process (fish_from, original, clipped, pixels); + babl_process (fish_to, clipped, destination, pixels); + babl_process (fish_from, destination, transformed, pixels); + + { + int i; + int log=0; + + for (i=0;iTOLERANCE) + { + if (!log) + log=1; + symmetric=0; + } + if (log && log < 5) + { + babl_log ("%s", babl->instance.name); + babl_log ("\ttest: %2.3f %2.3f %2.3f %2.3f", test [i*4+0], + test [i*4+1], + test [i*4+2], + test [i*4+3]); + babl_log ("\tclipped: %2.3f %2.3f %2.3f %2.3f", clipped [i*4+0], + clipped [i*4+1], + clipped [i*4+2], + clipped [i*4+3]); + babl_log ("\ttrnsfrmd: %2.3f %2.3f %2.3f %2.3f", transformed [i*4+0], + transformed [i*4+1], + transformed [i*4+2], + transformed [i*4+3]); + log++; + } + } + } + + babl_free (original); + babl_free (clipped); + babl_free (destination); + babl_free (transformed); + babl_free (test); + return symmetric; +} + BABL_CLASS_TEMPLATE (model) diff --git a/babl/babl-sanity.c b/babl/babl-sanity.c index 4f7c33e..b0e7b61 100644 --- a/babl/babl-sanity.c +++ b/babl/babl-sanity.c @@ -104,7 +104,7 @@ static int id_sanity (Babl *babl, void *user_data) { - if (0 == babl->instance.id && + if (0 && 0 == babl->instance.id && babl->instance.creator && !strcmp(BABL(babl->instance.creator)->instance.name, "BablBase")) { diff --git a/babl/babl-type.c b/babl/babl-type.c index 9edeeee..81d270e 100644 --- a/babl/babl-type.c +++ b/babl/babl-type.c @@ -19,6 +19,7 @@ #include #include +#include #include "babl-internal.h" #include "babl-db.h" @@ -138,4 +139,102 @@ babl_type_new (void *first_arg, } } + +#define TOLERANCE 0.000000001 +#define samples 512 + +double test[samples]; + +double r_interval (double min, double max) +{ + long int rand_i = random (); + double ret; + ret = (double) rand_i / RAND_MAX; + ret*=(max-min); + ret+=min; + return ret; +} + +void test_init (double min, double max) +{ + int i; + srandom (20050728); + for (i=0;itype.bits/8 * samples); + clipped = babl_calloc (1,64/8 * samples); + destination = babl_calloc (1,babl->type.bits/8 * samples); + transformed = babl_calloc (1,64/8 * samples); + + babl_process (fish_to, test, original, samples); + babl_process (fish_from, original, clipped, samples); + babl_process (fish_to, clipped, destination, samples); + babl_process (fish_from, destination, transformed, samples); + + { + int cnt=0; + int i; + for (i=0;i TOLERANCE) + { + if (cnt++<4) + babl_log ("%s: %f %f %f)", + babl->instance.name, test[i], clipped[i], transformed[i] + ); + is_symmetrical=0; + } + } + } + + babl_free (original); + babl_free (clipped); + babl_free (destination); + babl_free (transformed); + + return is_symmetrical; +} + BABL_CLASS_TEMPLATE (type) -- 2.30.2